﻿@page "/diagram/history-manager"

@using Syncfusion.Blazor.Diagrams
@using Syncfusion.Blazor.Buttons
@using Syncfusion.Blazor.Lists
@using Newtonsoft.Json;
@using Syncfusion.Blazor.Inputs
@using System.Collections.ObjectModel

@inherits SampleBaseComponent;

<SampleDescription>
 <p> This sample demonstrates viewing, deleting, and limiting diagram history as well as grouping diagram actions and storing them as a single entry in the history manager.</p>   
 <p style="font-weight: bold;">A new blazor diagram component which provides better performance than the existing diagram control in Blazor WebAssembly App. It is available in preview mode. Check the samples <a target='_blank' href='diagramcomponent/flowchart'>here</a>.</p>
</SampleDescription>
<ActionDescription>
   <p>Diagram history handles all the diagram history. Using the <a target='_blank' href='https://blazor.syncfusion.com/documentation/diagram/methods/#set-stack-limit'>SetStackLimit</a> method of the diagram, we limit the number of entries that can be stored in the diagram history. We can get the entries in the undo and redo lists using the <a target='_blank' href='https://blazor.syncfusion.com/documentation/diagram/methods/#get-history-stack'>GetHistoryStack(true)</a> and <a target='_blank' href='https://blazor.syncfusion.com/documentation/diagram/methods/#get-history-stack'>GetHistoryStack(false)</a> methods. We can group actions as a single entry with the <a target='_blank' href='https://blazor.syncfusion.com/documentation/diagram/methods/#group-action'>StartGroupAction</a> and <a target='_blank' href='https://blazor.syncfusion.com/documentation/diagram/methods/#group-action'>EndGroupAction</a> methods. Also, we can add custom entries to the diagram history.</p><br>
</ActionDescription>

<div class="col-lg-9 control-section" style="border-right: 1px solid #D7D7D7">
    <div id="diagram-space" class="content-wrapper">
        <SfDiagram Height="600px" @ref="@Diagram" Nodes="@NodeCollection" Connectors="@ConnectorCollection">
            <DiagramSnapSettings Constraints="@SnapConstraints.None"></DiagramSnapSettings>
            <DiagramEvents HistoryChanged="@HistoryChanged"></DiagramEvents>
            <DiagramPageSettings>
                <DiagramFitOptions CanFit="true" Mode="FitModes.Width"></DiagramFitOptions>
            </DiagramPageSettings>
        </SfDiagram>
    </div>

</div>
@*Hidden:Lines*@
<div id="historyPropertySection" class="col-lg-3 property-section">
    <div class="property-panel-header">
        History manager settings
    </div>

    <style>
        #listview, #listviewgrp {
            border: 1px solid #dddddd;
            border-radius: 3px;
        }

        .control-section {
            overflow: auto;
        }

        .property-panel-header {
            padding-top: 15px;
            padding-bottom: 5px;
            font-weight: 600;
            font-size: 15px;
        }

        .headingstyle {
            color: #807f7f;
            font-size: 15px;
            height: 50px;
            width: 100%;
            border-bottom: 1px solid #d9dedd;
            padding: 10px;
        }

        .e-btn, .e-css.e-btn {
            font-size: 14px;
        }

        #flat-list,
        #group-list {
            width: 49%;
            margin: auto;
            margin-bottom: 15px;
        }

            #flat-list h4, #group-list h4 {
                padding-left: 16px;
            }

        #flat-list {
            float: left;
            padding-left: 16px;
        }

        .e-listview:not(.e-list-template) .e-list-item {
            border: transparent;
        }

        #group-list {
            float: right;
            padding-right: 16px;
        }

        .row {
            margin-left: 0px;
            margin-right: 0px;
        }

        .undoListstyle {
            width: 100%;
            border: none;
        }
    </style>

    <div class="row property-panel-content" style="margin-left :0px;margin-right:0px" id="appearance">
        <div class="row property-panel-content" style="margin-left :0px;margin-right:0px">
            <div class="row">
                <div class="listbox" style="height:100%;border: 1px solid #e0e0e0">
                    <div class="headingstyle" style="height:40px">
                        <span>
                            Undo Stack
                        </span>
                        <div style="float: right; margin-top: -5px">
                            <SfButton Content="Undo" Disabled="@IsEnableUndoButton" @onclick="OnToggleClick"></SfButton>

                        </div>
                    </div>

                    <SfListView ID="undoList" CssClass="undoListstyle" Height="180px" DataSource="@Listdata">
                        <ListViewFieldSettings TValue="DataModel" Id="Text" Text="Text"></ListViewFieldSettings>
                    </SfListView>

                </div>
            </div>
            <div class="row">
                <div class="listbox" style="        height: 100%;
        border: 1px solid #e0e0e0">
                    <div class="headingstyle" style="height:40px">
                        <span>
                            Redo Stack
                        </span>
                        <div style="float: right; margin-top: -5px">
                            <SfButton Content="Redo" Disabled="@IsEnableRedoButton" @onclick="Redo"></SfButton>

                        </div>
                    </div>

                    <SfListView ID="Redo" CssClass="undoListstyle" Height="180px" DataSource="@RedoListdata">
                        <ListViewFieldSettings TValue="DataModel" Id="Text" Text="Text"></ListViewFieldSettings>
                    </SfListView>

                </div>
            </div>
            <div class="row" style="padding-top: 10px">
                <div style="display: table;height: 35px; padding-left: 0px" class="col-xs-6">
                    <div style="display: table-cell; vertical-align: middle">Stack Limit</div>
                </div>
                <div class="col-xs-6" style="padding-left: 0px; padding-right: 0px">
                    <SfNumericTextBox TValue="int" ID="StackLimit" Format="n0" Min="0" Value="@StackValue" Step="1">
                        <NumericTextBoxEvents TValue="int" ValueChange="@SetStackLimit"></NumericTextBoxEvents>
                    </SfNumericTextBox>
                </div>
            </div>
            <div class="row" style="padding-top: 10px">
                <div class="col-xs-6" style="padding-left: 0px;" title="Grouping the action">
                    <SfButton @ref="groupaction" Content="@actioncontent" @onclick="Startaction" IsToggle="true"></SfButton>
                </div>
                <div class="col-xs-6" style="padding-left: 16px;padding-right: 0px;">
                    <SfButton Content="Clear History" @onclick="Clearhistory"></SfButton>
                </div>
            </div>
        </div>
    </div>
</div>
@*End:Hidden*@

@code
    {
    SfDiagram Diagram;
    SfButton groupaction;
    bool IsEnableUndoButton = true;
    bool IsEnableRedoButton = true;
    private int StackValue = 0;
    string actioncontent = "Start Group Action";

    public async Task OnToggleClick(MouseEventArgs args)
    {
        await Diagram.Undo();
    }
    public async Task Redo(MouseEventArgs args)
    {
        await Diagram.Redo();
    }
    public async Task Startaction(MouseEventArgs args)
    {
        if (groupaction.Content == "Start Group Action")
        {
            actioncontent = "End Group Action";
            await Diagram.StartGroupAction();
        }
        else
        {
            actioncontent = "Start Group Action";
            await Diagram.EndGroupAction();
        }

        StateHasChanged();
    }
    public async Task Clearhistory(MouseEventArgs args)
    {
        await Diagram.ClearHistory();
        await this.Updatevalue();
    }

    public class DataModel
    {
        public string Text { get; set; }
        public DataModel(string text)
        {
            Text = text;

        }

    }
    public List<DataModel> Listdata = new List<DataModel>();
    public List<DataModel> RedoListdata = new List<DataModel>();

    public async Task HistoryChanged(IBlazorHistoryChangeArgs arg)
    {
        await this.Updatevalue();
    }

    public async Task SetStackLimit(Syncfusion.Blazor.Inputs.ChangeEventArgs<int> args)
    {
        StackValue = args.Value;
        await Diagram.SetStackLimit(args.Value);
    }
    public async Task Updatevalue()
    {
        List<DataModel> undoListdata = new List<DataModel>();
        List<DataModel> redoListdata = new List<DataModel>();
        List<HistoryEntry> undostack = await Diagram.GetHistoryStack(true);
        List<HistoryEntry> redostack = await Diagram.GetHistoryStack(false);
        IsEnableUndoButton = undostack.Count > 0 ? false : true;
        IsEnableRedoButton = redostack.Count > 0 ? false : true;
        for (int i = 0; i < undostack.Count; i++)
        {
            Dictionary<string, object> NewObject = JsonConvert.DeserializeObject<Dictionary<string, object>>(undostack[i].UndoObject.ToString());
            if (undostack[i].Type.ToString() != "CollectionChanged")
            {
                if (NewObject["nodes"].ToString() != "[]")
                {
                    undoListdata.Add(new DataModel("Node" + " " + undostack[i].Type.ToString()));
                }
                if (NewObject["connectors"].ToString() != "[]")
                {
                    undoListdata.Add(new DataModel("Connector" + " " + undostack[i].Type.ToString()));
                }
            }
            if (undostack[i].Type.ToString() == "CollectionChanged")
            {
                if (!undostack[i].UndoObject.ToString().Contains("sourceDecorator"))
                {
                    undoListdata.Add(new DataModel("Node" + " " + undostack[i].Type.ToString()));
                }
                if (undostack[i].UndoObject.ToString().Contains("sourceDecorator"))
                {
                    undoListdata.Add(new DataModel("Connector" + " " + undostack[i].Type.ToString()));
                }

            }
        }
        Listdata = undoListdata;
        for (int i = 0; i < redostack.Count; i++)
        {
            Dictionary<string, object> NewObject = JsonConvert.DeserializeObject<Dictionary<string, object>>(redostack[i].RedoObject.ToString());
            if (redostack[i].Type.ToString() != "CollectionChanged")
            {
                if (NewObject["nodes"].ToString() != "[]")
                {

                    redoListdata.Add(new DataModel("Node" + " " + redostack[i].Type.ToString()));

                }
                if (NewObject["connectors"].ToString() != "[]")
                {
                    redoListdata.Add(new DataModel("Connector" + " " + redostack[i].Type.ToString()));

                }


            }
            if (redostack[i].Type.ToString() == "CollectionChanged")
            {
                if (!redostack[i].UndoObject.ToString().Contains("sourceDecorator"))
                {

                    redoListdata.Add(new DataModel("Node" + " " + redostack[i].Type.ToString()));
                }
                if (redostack[i].UndoObject.ToString().Contains("sourceDecorator"))
                {

                    redoListdata.Add(new DataModel("Connector" + " " + redostack[i].Type.ToString()));

                }
            }

        }
        RedoListdata = redoListdata;

        StateHasChanged();
    }

    public ObservableCollection<DiagramNode> NodeCollection = new ObservableCollection<DiagramNode>();
    public ObservableCollection<DiagramConnector> ConnectorCollection = new ObservableCollection<DiagramConnector>();

    protected override void OnInitialized()
    {

        DiagramNode node1 = CreateNode("node1", 400, 30, FlowShapes.Terminator, "Start", "#FF4C4C", "#ffffff", 70, 40);
        DiagramNode node2 = CreateNode("node2", 400, 100, FlowShapes.Process, "Process", "#D7D7D7", "#111111", 70, 40);
        DiagramPort port1 = CreatePort(node2, "designPort", new NodePortOffset() { X = 0, Y = 0.5 });
        DiagramNode node3 = CreateNode("node3", 400, 180, FlowShapes.Process, "Coding", "#D7D7D7", "#111111", 70, 40);
        DiagramPort port2 = CreatePort(node3, "codingPort", new NodePortOffset() { X = 0, Y = 0.5 });
        DiagramNode node4 = CreateNode("node4", 400, 260, FlowShapes.Process, "Testing", "#D7D7D7", "#111111", 70, 40);
        DiagramNode node5 = CreateNode("node5", 400, 340, FlowShapes.Decision, "Errors?", "#56A1FF", "#ffffff", 80, 60);
        DiagramNode node6 = CreateNode("node6", 400, 430, FlowShapes.Process, "End", "#FF4C4C", "#ffffff", 70, 40);
        DiagramNode node7 = CreateNode("node7", 220, 180, FlowShapes.Decision, "Design \n error?", "#56A1FF", "#ffffff", 100, 60);
        DiagramPort n7port1 = CreatePort(node7, "porterror", new NodePortOffset() { X = 0.5, Y = 0 });
        DiagramPort n7port2 = CreatePort(node7, "portcoding", new NodePortOffset() { X = 1, Y = 0.5 });
        DiagramPort n7port3 = CreatePort(node7, "portdesign", new NodePortOffset() { X = 0.5, Y = 1 });
        CreateConnector("connector1", "node1", "node2");
        CreateConnector("connector2", "node2", "node3");
        CreateConnector("connector3", "node3", "node4");
        CreateConnector("connector4", "node4", "node5");
        CreateConnector("connector5", "node5", "node6");
        CreateConnector("connector6", "node5", "node7");
        CreateConnector("connector7", "node7", "node3", "portcoding", "codingPort");
        CreateConnector("connector8", "node7", "node2", "porterror", "designPort");
    }
    public void CreateConnector(string id, string sourceid, string targetid, string sourceportid = null, string targetportid = null)
    {
        DiagramConnector connector = new DiagramConnector()
        {
            Id = id,
            SourceID = sourceid,
            TargetID = targetid,
            SourcePortID = sourceportid,
            TargetPortID = targetportid,
            Type = Syncfusion.Blazor.Diagrams.Segments.Orthogonal,
            Style = new ConnectorShapeStyle() { StrokeColor = "#707070", StrokeWidth = 1.25 },
            TargetDecorator = new ConnectorTargetDecorator() { Style = new DecoratorShapeStyle() { Fill = "#707070", StrokeColor = "#707070" } }
        };
        if ((id == "connector5") || (id == "connector6") || (id == "connector7") || (id == "connector8"))
        {
            ObservableCollection<DiagramConnectorAnnotation> annotationcollection = new ObservableCollection<DiagramConnectorAnnotation>();
            DiagramConnectorAnnotation annotation = new DiagramConnectorAnnotation() { Style = new AnnotationStyle() { Fill = "white" } };
            if ((id == "connector5") || (id == "connector7"))
            {
                annotation.Content = "No";
            }
            else if ((id == "connector6") || (id == "connector8"))
            {
                annotation.Content = "Yes";
            }
            annotationcollection.Add(annotation);
            connector.Annotations = annotationcollection;
        };
        if (id == "connector6" || id == "connector7")
        {
            connector.Type = Segments.Orthogonal;
            DiagramConnectorSegment segment = new DiagramConnectorSegment() { Type = Segments.Orthogonal, Length = id == "connector7" ? 10 : 150, Direction = Direction.Left };
            connector.Segments = new ObservableCollection<DiagramConnectorSegment>() { segment };
        }
        ConnectorCollection.Add(connector);
    }

    public DiagramNode CreateNode(string id, double offx, double offy, FlowShapes shape, string content, string nodefill, string annotationcolor, int nodewidth, int nodeheight)
    {
        DiagramNode node = new DiagramNode()
        {
            Id = id,
            OffsetX = offx,
            OffsetY = offy,
            Width = nodewidth,
            Height = nodeheight,
            Shape = new DiagramShape() { Type = Syncfusion.Blazor.Diagrams.Shapes.Flow, FlowShape = shape },
            Style = new NodeShapeStyle() { Fill = nodefill, StrokeColor = "transparent" }
        };
        DiagramNodeAnnotation annotation = new DiagramNodeAnnotation()
        {
            Content = content,
            Style = new AnnotationStyle() { Color = annotationcolor }
        };
        node.Annotations = new ObservableCollection<DiagramNodeAnnotation>()
{
            annotation
        };
        NodeCollection.Add(node);
        return node;
    }
    public DiagramPort CreatePort(DiagramNode node, string pid, NodePortOffset offset)
    {
        DiagramPort port = new DiagramPort()
        {
            Id = pid,
            Offset = offset,
            Visibility = PortVisibility.Hidden
        };
        if (node.Ports == null)
        {
            node.Ports = new ObservableCollection<DiagramPort>();
        }
        (node.Ports as ObservableCollection<DiagramPort>).Add(port);

        return port;
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            await Task.Delay(500);
            await Diagram.SetStackLimit(StackValue);
        }
    }
}